```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Spring循环依赖深度解析</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            background-color: #f8fafc;
            color: #1e293b;
            line-height: 1.6;
        }
        .hero {
            background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%);
            color: white;
        }
        .code-block {
            font-family: 'Courier New', Courier, monospace;
            background-color: #1e293b;
            color: #f8fafc;
            border-radius: 0.5rem;
            overflow-x: auto;
        }
        .highlight {
            background-color: rgba(37, 99, 235, 0.1);
            border-left: 4px solid #2563eb;
        }
        .important-note {
            background-color: rgba(16, 185, 129, 0.1);
            border-left: 4px solid #10b981;
        }
        .warning-note {
            background-color: rgba(239, 68, 68, 0.1);
            border-left: 4px solid #ef4444;
        }
        .concept-card {
            transition: all 0.3s ease;
            border-radius: 0.5rem;
            box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
        }
        .concept-card:hover {
            transform: translateY(-4px);
            box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
        }
        .section-divider {
            border: none;
            height: 1px;
            background: linear-gradient(90deg, rgba(30, 41, 59, 0) 0%, rgba(30, 41, 59, 0.3) 50%, rgba(30, 41, 59, 0) 100%);
            margin: 3rem 0;
        }
    </style>
</head>
<body class="antialiased">
    <!-- Hero Section -->
    <section class="hero py-20 px-4 md:px-8">
        <div class="max-w-6xl mx-auto">
            <h1 class="text-4xl md:text-5xl font-bold mb-6 font-serif">Spring循环依赖深度解析</h1>
            <p class="text-xl md:text-2xl mb-8 opacity-90">探索Spring框架如何优雅处理Bean间的循环依赖问题</p>
            <div class="flex items-center">
                <span class="bg-white text-blue-700 px-4 py-2 rounded-full text-sm font-medium mr-3">Spring Framework</span>
                <span class="bg-white text-blue-700 px-4 py-2 rounded-full text-sm font-medium">依赖注入</span>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <main class="max-w-6xl mx-auto px-4 md:px-8 py-12">
        <!-- What is Circular Dependency -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center font-serif">
                <i class="fas fa-infinity text-blue-500 mr-3"></i>
                什么是循环依赖
            </h2>
            <div class="bg-white rounded-xl p-6 shadow-md mb-8">
                <p class="text-lg mb-4">循环依赖是指N个类循环（嵌套）引用，即N个Bean互相引用对方，最终形成<strong class="text-pink-500">闭环</strong>。</p>
                <div class="flex justify-center my-8">
                    <div class="w-full max-w-md">
                        <div class="mermaid">
                            graph LR
                                A[A] --> B[B]
                                B --> C[C]
                                C --> A
                        </div>
                    </div>
                </div>
                <div class="important-note p-4 my-6">
                    <p><i class="fas fa-info-circle text-green-500 mr-2"></i> Spring不鼓励使用循环引用，默认情况下是禁止使用的。Spring建议删除bean之间的循环依赖作为最后的手段。</p>
                </div>
            </div>
        </section>

        <!-- Types of Circular Dependency -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center font-serif">
                <i class="fas fa-code-branch text-blue-500 mr-3"></i>
                Spring Bean的循环依赖类型
            </h2>
            
            <!-- Field Injection -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold mb-4 flex items-center">
                    <i class="fas fa-square text-blue-400 mr-2"></i>
                    字段属性注入（Setter方法注入）循环依赖
                </h3>
                <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                    <div class="code-block p-4">
                        <pre><code>@Component
public class A { 
    @Autowired
    private B b;
}

@Component
public class B {
    @Autowired
    private A a;
}</code></pre>
                    </div>
                    <div>
                        <div class="bg-white rounded-xl p-6 shadow-md h-full flex flex-col">
                            <div class="mb-4">
                                <p class="font-medium mb-2">可以设置以下属性开启Spring解决循环依赖：</p>
                                <div class="code-block p-3 text-sm">
                                    <pre><code>spring.main.allow-circular-references=true</code></pre>
                                </div>
                            </div>
                            <div class="mt-auto">
                                <div class="important-note p-3">
                                    <p><i class="fas fa-info-circle text-green-500 mr-2"></i> 设置后项目可正常启动，注意SpringBoot版本问题（2.7.0及以上）。</p>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            
            <!-- Constructor Injection -->
            <div>
                <h3 class="text-2xl font-semibold mb-4 flex items-center">
                    <i class="fas fa-square text-blue-400 mr-2"></i>
                    构造器注入循环依赖
                </h3>
                <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                    <div class="code-block p-4">
                        <pre><code>@Service
public class A { 
    private B b;
    
    public A(B b) {
      this.b = b;
    }
}

@Service
public class B {
    private A a;
    
    public B(A a) {
        this.a = a;
    }
}</code></pre>
                    </div>
                    <div class="bg-white rounded-xl p-6 shadow-md">
                        <div class="warning-note p-4">
                            <p><i class="fas fa-exclamation-triangle text-red-500 mr-2"></i> 构造器注入构成的循环依赖<strong>无法解决</strong>，Spring会抛出<code class="bg-green-100 text-green-700 px-1 rounded">BeanCurrentlyInCreationException</code>异常。</p>
                        </div>
                        <div class="highlight p-4 mt-4">
                            <p><i class="fas fa-lightbulb text-blue-500 mr-2"></i> <strong>根本原因</strong>：Spring解决循环依赖依靠的是Bean的"<strong>中间态</strong>"概念，指已经实例化但未初始化的状态。构造器是完成实例化的东西，所以构造器的循环依赖无法解决。</p>
                        </div>
                    </div>
                </div>
            </div>
        </section>

        <hr class="section-divider">

        <!-- Three-Level Cache -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center font-serif">
                <i class="fas fa-layer-group text-blue-500 mr-3"></i>
                Spring容器的三级缓存
            </h2>
            <div class="bg-white rounded-xl p-6 shadow-md mb-8">
                <div class="code-block p-4 mb-6">
                    <pre><code>public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
    // 从上至下 分表代表这"三级缓存"
    private final Map&lt;String, Object&gt; singletonObjects = new ConcurrentHashMap<>(256); //一级缓存
    private final Map&lt;String, Object&gt; earlySingletonObjects = new HashMap<>(16); // 二级缓存
    private final Map&lt;String, ObjectFactory&lt;?&gt;&gt; singletonFactories = new HashMap<>(16); // 三级缓存
}</code></pre>
                </div>
                
                <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
                    <div class="concept-card bg-white p-6 shadow-sm border-t-4 border-blue-500">
                        <h3 class="text-xl font-semibold mb-3 flex items-center">
                            <i class="fas fa-database text-blue-500 mr-2"></i> 一级缓存
                        </h3>
                        <p class="text-gray-700">存储完全初始化好的Bean，可以直接使用。所有单例Bean初始化完成后会存放在这个Map中。</p>
                    </div>
                    <div class="concept-card bg-white p-6 shadow-sm border-t-4 border-green-500">
                        <h3 class="text-xl font-semibold mb-3 flex items-center">
                            <i class="fas fa-database text-green-500 mr-2"></i> 二级缓存
                        </h3>
                        <p class="text-gray-700">存储提前暴露的Bean（已实例化但未初始化），用于解决循环依赖问题。</p>
                    </div>
                    <div class="concept-card bg-white p-6 shadow-sm border-t-4 border-purple-500">
                        <h3 class="text-xl font-semibold mb-3 flex items-center">
                            <i class="fas fa-database text-purple-500 mr-2"></i> 三级缓存
                        </h3>
                        <p class="text-gray-700">存储Bean工厂，用于处理存在AOP代理时的循环依赖情况。</p>
                    </div>
                </div>
            </div>
        </section>

        <!-- Bean Creation Process -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 flex items-center font-serif">
                <i class="fas fa-cogs text-blue-500 mr-3"></i>
                Spring创建Bean的流程
            </h2>
            <div class="bg-white rounded-xl p-6 shadow-md mb-8">
                <div class="flex justify-center mb-8">
                    <img src="https://cdn.nlark.com/yuque/0/2021/png/21449790/1631437071746-730e96e7-32ae-4f24-a98b-48ce354b34e7.png" alt="Spring创建Bean流程" class="rounded-lg shadow">
                </div>
                <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
                    <div class="bg-blue-50 p-4 rounded-lg">
                        <h4 class="font-bold text-blue-700 mb-2"><i class="fas fa-cube mr-2"></i>createBeanInstance</h4>
                        <p>实例化，调用对象的构造方法实例化对象</p>
                    </div>
                    <div class="bg-green-50 p-4 rounded-lg">
                        <h4 class="font-bold text-green-700 mb-2"><i class="fas fa-paint-brush mr-2"></i>populateBean</h4>
                        <p>填充属性，对bean的依赖属性进行注入(@Autowired)</p>
                    </div>
                    <div class="bg-purple-50 p-4 rounded-lg">
                        <h4 class="font-bold text-purple-700 mb-2"><i class="fas fa-check-circle mr-2"></i>initializeBean</h4>
                        <p>初始化，处理Aware接口并执行各类bean后处理器</p>
                    </div>
                </div>
                <div class="highlight p-4 mt-6">
                    <p><i class="fas fa-lightbulb text-blue-500 mr-2"></i> 循环依赖主要发生在<strong>第二步（populateBean）</strong>，也就是field属性注入的处理阶段。</p>
                </div>
            </div>
        </section>

        <!-- Cache Details -->
        <section class="mb-16">
            <h2 class="text-3xl font-bold mb-6 font-serif">三级缓存详解</h2>
            
            <!-- Level 1 Cache -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold mb-4 flex items-center">
                    <span class="bg-blue-500 text-white rounded-full w-8 h-8 flex items-center justify-center mr-3">1</span>
                    一级缓存的作用
                </h3>
                <div class="bg-white rounded-xl p-6 shadow-md">
                    <p class="mb-4">一级缓存(<code class="bg-gray-100 px-1 rounded">singletonObjects</code>)存储完全初始化好的Bean，可以直接使用。Spring中的缓存底层都是一个Map，所有单例的bean初始化完成后会存放在这个Map中，beanName为key，单例bean为value。</p>
                    <div class="important-note p-4">
                        <p><i class="fas fa-info-circle text-green-500 mr-2"></i> 没有循环依赖情况下，只有一级缓存生效，二三级缓存用不到。</p>
                    </div>
                </div>
            </div>
            
            <!-- Level 2 Cache -->
            <div class="mb-12">
                <h3 class="text-2xl font-semibold mb-4 flex items-center">
                    <span class="bg-green-500 text-white rounded-full w-8 h-8 flex items-center justify-center mr-3">2</span>
                    二级缓存的作用
                </h3>
                <div class="bg-white rounded-xl p-6 shadow-md">
                    <p class="mb-4">二级缓存(<code class="bg-gray-100 px-1 rounded">earlySingletonObjects</code>)存储提前暴露的Bean（已实例化但未初始化），用于解决循环依赖问题。</p>
                    <p class="mb-4">当初始化A时发现A依赖B，而B还没有初始化，会暂停A先去初始化B。此时new出来的A对象（半成品）不能直接放在一级缓存中，而是放在二级缓存中，标记为创建中的Bean，供其他Bean依赖。</p>
                    <div class="highlight p-4">
                        <p><i class="fas fa-lightbulb text-blue-500 mr-2"></i> 二级缓存是真正解决循环依赖的关键，简单的应用场景通常不会出现循环依赖，只有复杂的业务中可能出现。</p>
                    </div>
                </div>
            </div>
            
            <!-- Level 3 Cache -->
            <div>
                <h3 class="text-2xl font-semibold mb-4 flex items-center">
                    <span class="bg-purple-500 text-white rounded-full w-8 h-8 flex items-center justify-center mr-3">3</span>
                    三级缓存的作用
                </h3>
                <div class="bg-white rounded-xl p-6 shadow-md">
                    <p class="mb-4">三级缓存(<code class="bg-gray-100 px-1 rounded">singletonFactories</code>)存储Bean工厂，用于处理存在AOP代理时的循环依赖情况。</p>
                    <p class="mb-4">当Bean需要AOP代理增强时，Spring的设计是在Bean初始化完成后才进行代理。三级缓存可以在存在循环依赖并且需要AOP代理时，提前完成代理增强。</p>
                    <div class="important-note p-4">
                        <p><i class="fas fa-info-circle text-green-500 mr-2"></i> 三级缓存主要预防Bean有依赖时还可以完成代理增强，保持与Spring设计一致（代理增强在初始化完成后）。</p>
                    </div>
                </div>
            </div>
        </section>

        <hr class="section-divider">

        <!-- Summary -->
        <section>
            <h2 class="text-3xl font-bold mb-6 flex items-center font-serif">
                <i class="fas fa-check-circle text-blue-500 mr-3"></i>
                总结
            </h2>
            <div class="bg-white rounded-xl p-6 shadow-md">
                <p class="mb-6">以A、B类使用属性(field)注入循环依赖为例，对整个流程做文字步骤总结如下：</p>
                
                <div class="space-y-4">
                    <div class="flex items-start">
                        <div class="bg-blue-500 text-white rounded-full w-6 h-6 flex items-center justify-center flex-shrink-0 mt-1 mr-3">1</div>
                        <p>使用<code class="bg-gray-100 px-1 rounded">context.getBean(A.class)</code>获取容器内的单例A，初次获取A不存在，走A的创建流程</p>
                    </div>
                    <div class="flex items-start">
                        <div class="bg-blue-500 text-white rounded-full w-6 h-6 flex items-center justify-center flex-shrink-0 mt-1 mr-3">2</div>
                        <p>实例化A（仅仅是实例化），并将它放进缓存（此时A已经实例化完成，可以被引用）</p>
                    </div>
                    <div class="flex items-start">
                        <div class="bg-blue-500 text-white rounded-full w-6 h-6 flex items-center justify-center flex-shrink-0 mt-1 mr-3">3</div>
                        <p>属性注入A：<code class="bg-gray-100 px-1 rounded">@Autowired</code>依赖注入B（此时需要去容器内获取B）</p>
                    </div>
                    <div class="flex items-start">
                        <div class="bg-blue-500 text-white rounded-full w-6 h-6 flex items-center justify-center flex-shrink-0 mt-1 mr-3">4</div>
                        <p>为了完成依赖注入B，会通过<code class="bg-gray-100 px-1 rounded">getBean(B)</code>去容器内找B。此时B不存在，走B的创建流程</p>
                    </div>
                    <div class="flex items-start">
                        <div class="bg-blue-500 text-white rounded-full w-6 h-6 flex items-center justify-center flex-shrink-0 mt-1 mr-3">5</div>
                        <p>实例化B，并将其放入缓存（此时B也能够被引用）</p>
                    </div>
                    <div class="flex items-start">
                        <div class="bg-blue-500 text-white rounded-full w-6 h-6 flex items-center justify-center flex-shrink-0 mt-1 mr-3">6</div>
                        <p>属性注入B：<code class="bg-gray-100 px-1 rounded">@Autowired</code>依赖注入A（此时需要去容器内获取A）</p>
                    </div>
                    <div class="flex items-start">
                        <div class="bg-blue-500 text-white rounded-full w-6 h-6 flex items-center justify-center flex-shrink-0 mt-1 mr-3">7</div>
                        <p>初始化B时会调用<code class="bg-gray-100 px-1 rounded">getBean(A)</code>去容器内找到A，此时A已在缓存中</p>
                    </div>
                    <div class="flex items-start">
                        <div class="bg-blue-500 text-white rounded-full w-6 h-6 flex items-center justify-center flex-shrink-0 mt-1 mr-3">8</div>
                        <p>B初始化成功（已注入A成功），返回到A的初始化流程</p>
                    </div>
                    <div class="flex items-start">
                        <div class="bg-blue-500 text-white rounded-full w-6 h-6 flex items-center justify-center flex-shrink-0 mt-1 mr-3">9</div>
                        <p>因为B实例已成功返回，A也初始化成功</p>
                    </div>
                    <div class="flex items-start">
                        <div class="bg-blue-500 text-white rounded-full w-6 h-6 flex items-center justify-center flex-shrink-0 mt-1 mr-3">10</div>
                        <p>最终，B持有的是初始化完成的A，A持有的是初始化完成的B</p>
                    </div>
                </div>
                
                <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mt-8">
                    <div class="concept-card bg-white p-6 shadow-sm border border-blue-100">
                        <h3 class="text-xl font-semibold mb-3">一级缓存</h3>
                        <p class="text-gray-700">存储完全初始化好的Bean，没有循环依赖时只有一级缓存生效</p>
                    </div>
                    <div class="concept-card bg-white p-6 shadow-sm border border-green-100">
                        <h3 class="text-xl font-semibold mb-3">二级缓存</h3>
                        <p class="text-gray-700">存储提前暴露的Bean，真正解决循环依赖的核心</p>
                    </div>
                    <div class="concept-card bg-white p-6 shadow-sm border border-purple-100">
                        <h3 class="text-xl font-semibold mb-3">三级缓存</h3>
                        <p class="text-gray-700">存储Bean工厂，处理需要AOP代理时的循环依赖情况</p>
                    </div>
                </div>
            </div>
        </section>
    </main>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            }
        });
    </script>
</body>
</html>
```